home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
201-225
/
214
/
smarticon
/
src
/
icon.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-13
|
17KB
|
559 lines
/***************************************************************************/
/* */
/* SmartIcon, release 1.0 - An Intuition object iconifier for the Amiga */
/* Copyright (c) 1988 Gauthier H. Groult */
/* */
/* Written in January 1988 by Gauthier H. Groult */
/* 33, Boulevard Saint Denis, */
/* 92400 Courbevoie */
/* France - Europe */
/* Tel: (16) 1 47 89 09 54 */
/* email: mcvax!inria!litp!germinal!groult */
/* */
/* This source code is not in public domain, please do not distribute. */
/* The binary program is shareaware. Read docs files for details. */
/* */
/***************************************************************************/
/* */
/* SmartIcon Tech Notes. */
/* */
/* The general techniques used in the program are the following: */
/* */
/* ° The program keeps track of what as been patched trouch a linked */
/* list of "IconGadgets". The structure IconGadget is a superset */
/* of the Gadget structure. The added fields contains the information */
/* needed to reset things when cleaning up. */
/* */
/* ° The windows that are already opened when the program starts are */
/* patched by scanning the Intuition window list. */
/* */
/* ° The windows which open *after* the program as been laoded are */
/* patched trough a rom call trap to OpenWindow(). */
/* */
/* ° The windows that close *while* the program is running are */
/* un-patched trough a rom call trap to CloseWindow(). */
/* */
/* ° The icon gadgets selection for any window is detected to a rom */
/* call trap to PutMsg(). */
/* */
/* ° For every icon created, a program capable of un-iconifying the */
/* window is written to the ram disk. This program is contained in */
/* this code, under its binary form. */
/* */
/* ° The revealing program needs to have a pointer on the window it */
/* must reveal. This is given to it trough the "comment" field of */
/* the window's icon. */
/* */
/* ° The revealing program self-destroys it's ram-disk file before */
/* exiting to keep things clean. */
/* */
/* ° The windows are hidden only by resizing and moving their layers. */
/* */
#include "exec/types.h"
#include "graphics/gfx.h"
#include "hardware/dmabits.h"
#include "hardware/custom.h"
#include "hardware/blit.h"
#include "graphics/gfxmacros.h"
#include "graphics/copper.h"
#include "graphics/view.h"
#include "graphics/gels.h"
#include "graphics/regions.h"
#include "graphics/clip.h"
#include "exec/exec.h"
#include "graphics/text.h"
#include "graphics/gfxbase.h"
#include "graphics/layers.h"
#include "graphics/clip.h"
#include "intuition/intuition.h"
#include "intuition/intuitionbase.h"
#include "libraries/dos.h"
#include "workbench/workbench.h"
#include "string.h"
/*
#include "proto/exec.h"
#include "proto/intuition.h"
#include "proto/dos.h"
*/
#define ICONGADGET 11366
#define MAXFILELEN 13
struct IconGadget
{
struct IconGadget *NextIGadget;
struct Gadget *IconGadget, *DepthGadget;
struct Window *Window;
struct MsgPort *ReelPort;
ULONG Flags;
};
BOOL HooksSet;
ULONG IconEvent;
ULONG IconBase;
struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;
struct LayersBase *LayersBase;
struct MsgPort *IconPort;
struct IconGadget AddedGadgets;
struct Task *IconTask;
struct Window *theSelectedWindow;
struct FileHandle *file;
extern UBYTE RevealCode[];
extern USHORT RevealCodeSize;
extern USHORT IconImageData[], theWindowIData[];
extern VOID SetHooks(), CleanHooks(), DisplayWindow();
struct Image IconImage =
{
-14,0,
51,10,
2,
IconImageData,
0x0003,0x0000,
NULL
};
struct Gadget theIconGadget =
{
NULL,
-36, 0, 17, 10,
GADGIMAGE | GRELRIGHT,
RELVERIFY,
BOOLGADGET,
(APTR)&IconImage,
NULL,
NULL,
NULL,
NULL,
ICONGADGET,
NULL
};
struct Image theWindowImage = {
0,0,
55,20,
2,
&theWindowIData[0],
3,0
};
struct DiskObject theWindowIcon = {
WB_DISKMAGIC,
WB_DISKVERSION,
/* Gadget Structure */
NULL, /* Ptr to next gadget */
0,0, /* Leftedge, Topedge */
55,20, /* Width, Height */
GADGHBOX|GADGIMAGE, /* Flags */
RELVERIFY|GADGIMMEDIATE, /* Activation */
BOOLGADGET, /* Type */
(APTR)&theWindowImage, /* Render */
NULL, /* Select Render */
NULL, /* Text */
NULL,NULL,NULL,NULL, /* Exclude, Special, ID, UserData */
WBTOOL, /* WBObject type */
NULL, /* Default tool */
NULL, /* Tool Types */
NO_ICON_POSITION, /* Current X */
NO_ICON_POSITION, /* Current Y */
NULL,NULL,NULL, /* Drawer, ToolWindow, Stack */
};
VOID main(), Cleanup(), DepthGadgetsHNone(), Expurge(),
AddIconGadget(), HideWindow(), RevealWindow(), Recover();
VOID MyOpenWindow(), MyCloseWindow(), MyPutMsg();
struct IconGadget *AllocIGadget(), *FindIGadget();
/* Main() calls the initialisation functions (the startup window and the */
/* library hooks); scans the Intuition window list to patch all depth */
/* gadgets for already opened windows; and wait forever for icon messages. */
VOID
main(argc, argv)
UBYTE argc, **argv;
{
UBYTE mystring[80], filename[MAXFILELEN+10], comment[20];
ULONG mask, IconPortMsg;
struct Screen *screen;
struct Window *window, *iwindow;
struct IntuiMessage *message;
GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0);
if (!GfxBase) Cleanup(10);
IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library", 0);
if (!IntuitionBase) Cleanup(11);
LayersBase = (struct LayersBase *)OpenLibrary("layers.library", 0);
if (!LayersBase) Cleanup(12);
IconBase = OpenLibrary("icon.library",0);
if (!IconBase) Cleanup(13);
if (strcmp(argv[1],"-f")) DisplayWindow();
IconTask = (struct Task *)FindTask(0);
IconEvent = AllocSignal(-1);
if (IconEvent == -1) Cleanup(21);
IconPort = (struct MsgPort *)CreatePort(0, 0); /* The message port for */
if (!IconPort) Cleanup(22); /* where icon msgs are */
IconPortMsg = 1 << IconPort->mp_SigBit; /* posted. */
SetHooks();
HooksSet = TRUE;
screen = IntuitionBase->FirstScreen; /* First system screen */
while (screen)
{
window = screen->FirstWindow; /* First system window */
while (window)
{
if (window->Title && (window->Flags & WINDOWDEPTH))
{
AddIconGadget(window);
}
window = window->NextWindow;
}
screen = screen->NextScreen;
}
for(;;)
{
mask = Wait(SIGBREAKF_CTRL_C | IconPortMsg | IconEvent);
if (mask & SIGBREAKF_CTRL_C)
Cleanup(0);
if (mask & IconEvent)
while (message=(struct IntuiMessage *)GetMsg(IconPort))
ReplyMsg(message);
if (mask & IconEvent)
{
Forbid();
iwindow = theSelectedWindow;
HideWindow(iwindow->WScreen, iwindow);
strcpy(mystring, iwindow->Title);
mystring[MAXFILELEN]=0;
Expurge(mystring);
sprintf(filename, "ram:%s", mystring);
if (!(file = (struct FileHandle *)Open(filename, MODE_NEWFILE)))
{
DisplayBeep(NULL);
RevealWindow(iwindow->WScreen, iwindow);
}
else
{
Write(file, RevealCode, RevealCodeSize);
Close(file);
sprintf(comment, "%ld", iwindow);
if (!SetComment(filename, comment)) Recover(filename, iwindow);
else if (!PutDiskObject(filename, &theWindowIcon))
Recover(filename, iwindow);
}
Permit();
}
}
}
/* Expurge() retrieves all special caracters used by AmigaDos from */
/* a string. This is used to purge window titles, for they are used as */
/* the file name for the icon. */
VOID
Expurge(text)
UBYTE *text;
{
while (*text)
{
if (*text == ':' || *text == '/' || *text == ' ')
strcpy(text, text+1);
else text++;
}
}
/* This function is called when attempting to iconify fails. It just */
/* undoes what as already be done. Its sole purpose as a function is */
/* to evitate a "goto". */
VOID
Recover(fname, window)
UBYTE *fname;
struct Window *window;
{
DeleteFile(fname);
DisplayBeep(NULL);
RevealWindow(window->WScreen, window);
}
/* This function adds the new depth gadgets to a window. Dynamic */
/* allocation is required as we use a linked list (nodes) for the */
/* modified windows. Instead of just allocating and filling the */
/* gadget structyre, we CopyMemQuick() it for speed. */
VOID
AddIconGadget(window)
struct Window *window;
{
struct IconGadget *node;
Forbid();
node = AllocIGadget();
node->Window = window;
DepthGadgetsHNone(node);
CopyMemQuick(&theIconGadget, node->IconGadget, sizeof(struct Gadget));
if (window->Flags & GIMMEZEROZERO)
node->IconGadget->GadgetType |= GZZGADGET;
AddGadget(window, node->IconGadget, 0);
RefreshGList(window->FirstGadget, window, NULL, 1);
if (!window->UserPort) window->UserPort = IconPort;
ModifyIDCMP(window, window->IDCMPFlags);
Permit();
}
/* AllocIGadget(): allocates an IconGadget. IconGadgets are actually a */
/* superset of the gadget structure. The linked list of allocated */
/* IconGadgets is the only way we know about which windows have been */
/* modified. */
struct IconGadget
*AllocIGadget()
{
struct IconGadget *node;
node = (struct IconGadget *)
AllocMem(sizeof(struct IconGadget), MEMF_CLEAR);
node->NextIGadget = AddedGadgets.NextIGadget;
AddedGadgets.NextIGadget = node;
node->IconGadget = (struct Gadget *)
AllocMem(sizeof(struct Gadget), MEMF_CLEAR);
return(node);
}
/* DepthGadgetsHNone() changes the position and size of the original depth */
/* gadgets so they can match the new imagery. The name of this function */
/* doesn't discribe it's meaning, it just there for historical reasons. */
VOID
DepthGadgetsHNone(node)
struct IconGadget *node;
{
struct Gadget *gadget;
struct Window *window;
window = node->Window;
gadget = window->FirstGadget;
while (gadget)
{
if (!gadget->TopEdge)
if (gadget->LeftEdge == -28)
{
node->DepthGadget = gadget;
gadget->LeftEdge = -20;
gadget->Width = 18;
}
else if (gadget->LeftEdge == -52) gadget->Width = 17;
gadget = gadget->NextGadget;
}
}
/* HideWindow().
/* This is the key to window iconification. This call removes the window */
/* from the display without releasing any of it's attributes. This is */
/* sort of a visual trick: the layer of the window is made small (one */
/* pixel), and is moved to the lower rightmost position of the display. */
/* Thus the window is invisible, but it keeps it's rastport, bitmap, */
/* gadgets, etc... The only way the trick can be seen is by checking */
/* Intuition's window list, or by using a program such as DropShadow */
/* which highlights window levels. */
/* This screws up with programs messing with layers, of course, but */
/* they are pretty rare. */
/* */
/* One good question is: does this work the same way with screens?? */
VOID
HideWindow(screen, window)
struct Screen *screen;
struct Window *window;
{
struct Layer *layer;
struct Layer_Info *linfo;
layer = window->RPort->Layer;
linfo = layer->LayerInfo;
SizeLayer(linfo, layer, 1-window->Width, 1-window->Height);
MoveLayer(linfo, layer,
screen->Width - window->LeftEdge - 1,
screen->Height - window->TopEdge - 1);
ShowTitle(screen, TRUE);
MakeScreen(screen);
}
/* RevealWindow() is the exact opposition of HideWindow(). It resizes and */
/* puts back to its original position the window's layer. The nice thing */
/* about it is that we DO NOT need to give it the position where to move */
/* to: this is described by the window itself! */
/* */
/* This function is not actually called within THIS program. It's in the */
/* code for it's a good place for it to be. It is called by the "Reveal" */
/* program which is encoded in and written to disk by this program. */
VOID
RevealWindow(screen, window)
struct Screen *screen;
struct Window *window;
{
struct Layer *layer;
struct Layer_Info *linfo;
layer = window->RPort->Layer;
linfo = layer->LayerInfo;
MoveLayer(linfo, layer,
window->LeftEdge - screen->Width + 1,
window->TopEdge - screen->Height + 1);
SizeLayer(linfo, layer, window->Width-1, window->Height-1);
WindowToFront(window);
}
/* This where a rom call to OpenWindow() ends to. If the new window has */
/* depth gadgets, than add an icon to it. */
VOID
MyOpenWindow(window)
struct Window *window;
{
if (window && window->Title && (window->Flags & WINDOWDEPTH))
AddIconGadget(window);
}
/* This is where a rom call to CloseWindow() comes before actually */
/* closing the window. The jump to the rom code is done when returning */
/* from this function (see hook.asm). */
/* If the window has been patched, then deallocate what was ealier */
/* given to it. */
VOID
MyCloseWindow(window)
struct Window *window;
{
struct IconGadget *node, *next;
Forbid();
if (node = FindIGadget(window))
{
next = node->NextIGadget;
RemoveGadget(window, next->IconGadget);
FreeMem(next->IconGadget, sizeof(struct Gadget));
if (window->UserPort==IconPort) window->UserPort = NULL;
node->NextIGadget = next->NextIGadget;
FreeMem(next, sizeof(struct IconGadget));
}
Permit();
}
/* MyPutMsg(). This is another trick. */
/* How can we get the messages from the icon gadgets? The only way I */
/* figured out is by trapping all the PutMsg() calls. Thus every time */
/* there's a PutMsg(), you first come here. */
/* Now we had to signal our main() that we recognized an icon gadget */
/* message. Doing this by a PutMsg wasn't possible: as the function is */
/* trapped, using it in the trap leads to an infinite loop. So we */
/* use a signal. */
VOID
MyPutMsg(port, msg)
struct MsgPort *port;
struct IntuiMessage *msg;
{
if ( msg->Class == GADGETUP &&
((struct Gadget *)(msg->IAddress))->GadgetID == ICONGADGET )
{
theSelectedWindow = msg->IDCMPWindow;
Signal(IconTask, IconEvent);
}
}
/* FindIGadget() returns an IconGadget given a window pointer, i.e. */
/* finds back the allocated memory from an IntuiMessage IDCMPWindow */
/* field. */
struct IconGadget
*FindIGadget(window)
struct Window *window;
{
struct IconGadget *ig;
ig = &AddedGadgets;
while (ig->NextIGadget)
{
if (ig->NextIGadget->Window == window) return(ig);
ig = ig->NextIGadget;
}
return(NULL);
}
/* Cleanup() de-patches all patched windows, closes everything and leaves. */
/* Currently called only when a "Break C" is sent to the task. */
VOID
Cleanup(code)
UBYTE code;
{
struct IconGadget *node, *next;
struct IntuiMessage *msg;
if (code>11) DisplayBeep(NULL);
if (HooksSet) CleanHooks();
Forbid();
node = AddedGadgets.NextIGadget;
while (node)
{
next = node->NextIGadget;
RemoveGadget(node->Window, node->IconGadget);
node->DepthGadget->LeftEdge = -28;
node->DepthGadget->Width = 26;
node->DepthGadget->NextGadget->Width = 24;
RefreshGList(node->DepthGadget, node->Window, NULL, 2);
FreeMem(node->IconGadget, sizeof(struct Gadget));
FreeMem(node, sizeof(struct IconGadget));
node = next;
}
Permit();
if (IconPort)
{
while(msg = (struct IntuiMessage *)GetMsg(IconPort)) ReplyMsg(msg);
DeletePort(IconPort);
}
FreeSignal(IconEvent);
if (IconBase) CloseLibrary(IconBase);
if (GfxBase) CloseLibrary(GfxBase);
if (IntuitionBase) CloseLibrary(IntuitionBase);
if (LayersBase) CloseLibrary(LayersBase);
exit(code);
}